﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using FFmpegVideoClip.Lib;
using FFmpegVideoClip.Mode.Files;
using PropertyChanged;
using UtilityToolsCollect.DataCollection;

namespace FFmpegVideoClip.Mode
{
    internal interface IProgressStatistics
    {
        public string Name { get; set; }
        public string DisplayName { get; }
        public string SchemesNames { get; }
        public double ProgressValue { get; set; }
        public string TimeRemaining { get; set; }
        public ObservableCollection<ISubItem> ProgressItems { get; set; }
        public ObservableCollection<ISubItem> AfterprocessingProgressItems { get; set; }
        public double TotalSeconds { get; set; }
        public TimeSpan Duration { get; set; }
        public string DisplayDuration { get; }
        public double CompletedSeconds { get;}
        public bool IsCompleted { get; }
        public int CompletedCount { get; }
        public int ChildsCount { get; }
        public void Add(int ID, string Name, TimeSpan DurationTime, SuccessAndProgress successAndProgress, bool IsAfterprocessingElement = false);
        public bool ContainsKey(int FragmentID);
        public void Release();
        void Update(int ID, TimeSpan? FragmentDuration, SuccessAndProgress? successAndProgress);
    }
    internal interface ISubItem
    {
        public ObservableCollection<SuccessAndProgressData> SuccessAndProgressDatas { get; set; }
        public string DisplayName { get; }
        public string SchemesNames { get; }
        public double ProgressValue { get; set; }
        public string TimeRemaining { get; set; }
        public double Speed { get; set; }
        public double TotalSeconds { get; set; }
        public TimeSpan Duration { get; set; }
        public string DisplayDuration { get; }
        public double CompletedSeconds { get; }
        public bool IsCompleted { get; }
        public int CompletedCount { get; }
        public int ChildsCount { get; }
        public TimeSpan RunTime { get; set; }
        public void Release();
        public void Update(TimeSpan? FragmentDuration, SuccessAndProgress? successAndProgress);
    }
    [AddINotifyPropertyChangedInterface]
    internal class ProgressStatistics : INotifyPropertyChanged
    {
        //public static ProgressStatistics? m_Instance = new ProgressStatistics()
        //{
        //    ProgressStatisticsList = new ObservableCollection<IProgressStatistics>()
        //     {
        //         new FileProgressStatistics() { Name="a", ProgressValue=100d ,TimeRemaining="剩余:[00:00:00]" , TotalSeconds=200d},
        //         new FileProgressStatistics() { Name="b", ProgressValue=50d ,TimeRemaining="剩余:[00:00:00]" , TotalSeconds=200d},
        //         new FileProgressStatistics() { Name="b", ProgressValue=50.26d ,TimeRemaining="剩余:[00:00:00]" , TotalSeconds=200d}
        //     }
        //};
        //public static ProgressStatistics? m_Instance = new ProgressStatistics()
        //{
        //    ProgressStatisticsList = new ObservableCollection<IProgressStatistics>()
        //     {
        //         new ClipProgressStatistics() { Name="abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", ProgressValue=68.99d , TimeRemaining="剩余:[00:00:00]",TotalSeconds=50000d ,ProgressItems=new ObservableCollection<ISubItem>()
        //         {
        //             new FragmentProgressStatistics() { Name="a1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", ProgressValue=68.99d,TimeRemaining="剩余:[00:00:00]" , TotalSeconds=15000d , SuccessAndProgressDatas= new ()
        //             {
        //                 new SuccessAndProgressData(null){ ProgressValue=75d, TimeRemaining="剩余:[00:00:00]" },
        //                 new SuccessAndProgressData(null){ ProgressValue=35d, TimeRemaining="剩余:[00:00:00]" },
        //             } },
        //             new FragmentProgressStatistics() { Name="a2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", ProgressValue=50.2d, TimeRemaining = "剩余:[00:00:00]",TotalSeconds=30000d}
        //         }, AfterprocessingProgressItems=new ObservableCollection<ISubItem>() 
        //         {
        //             new FragmentProgressStatistics() { Name="后处理", ProgressValue=68.99d,TimeRemaining="剩余:[00:00:00]" , TotalSeconds=15000d , SuccessAndProgressDatas= new ()
        //             {
        //                 new SuccessAndProgressData(null){ SchemeName="后处理1" ,ProgressValue=35d, TimeRemaining="剩余:[00:00:00]" },
        //                  new SuccessAndProgressData(null){SchemeName="后处理2" , ProgressValue=35d, TimeRemaining="剩余:[00:00:00]" },
        //             } }
        //         }
        //         },

        //     }
        //};
        public readonly record struct ProgressValue(double Progress_Value, double TotalValue) { public double RatioValue => (Progress_Value / TotalValue).GetValid(); }

        public static ProgressStatistics? m_Instance;
        public static ProgressStatistics Instance
        {
            get
            {
                if (m_Instance == null)
                    m_Instance = new ProgressStatistics();
                return m_Instance;
            }
        }
        public static void RemoveClip(string ClipName) => Instance.Remove(ClipName);
        public static void Clear()
        {
            if (m_Instance == null)
                return;
            m_Instance.ProgressStatisticsList.ForEach(x => x.Release());
            m_Instance.ProgressStatisticsList.Clear();
        }

        public static void AddElement(string ClipName, string FragmentName, int FragmentID, TimeSpan FragmentDuration, SuccessAndProgress successAndProgress, bool IsAfterprocessingElement = false)
            => Tools.UIThreadBeginInvoke(() => Instance.Add(ClipName, FragmentName, FragmentID, FragmentDuration, successAndProgress, IsAfterprocessingElement));
        public static void AddElement(string FilePath, TimeSpan FileDuration, SuccessAndProgress successAndProgress)
            => Tools.UIThreadBeginInvoke(() => Instance.Add(FilePath, FileDuration, successAndProgress));
        public static void UpdateElement(int ID, TimeSpan? FragmentDuration, SuccessAndProgress? successAndProgress) => Instance.Update(ID, FragmentDuration, successAndProgress);
        public static void WriteLOG(string value, bool ForceWrite = false)
        {
            double Total = 0d, Current = 0d;
            foreach (SuccessAndProgress item in Instance.successAndProgresses)
            {
                Total += item.TotalSeconds;
                Current += item.CompletedTimingSeconds;
            }
            LogManage.WriteLineNewInfo($"[{value}];总计:[{Math.Round(Current, 2, MidpointRounding.AwayFromZero)}/{Math.Round(Total, 2, MidpointRounding.AwayFromZero)}]", ForceWrite);
        }
        //************************************************************//
        public event PropertyChangedEventHandler? PropertyChanged;
        public void SendPropertyChanged(string PropertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        public ObservableCollection<SuccessAndProgress> successAndProgresses { get; private set; } = new();
        public ObservableCollection<IProgressStatistics> ProgressStatisticsList { get; private set; } = new();
        public ObservableCollection<IProgressStatistics> ProgressStatisticsListDesign { get; private set; } = new() { new ClipProgressStatistics() { Name="测试数据",ProgressValue=20,TimeRemaining="123",TotalSeconds=100,Duration=TimeSpan.FromHours(1),ProgressItems=new() { new FragmentProgressStatistics() 
        {
            Name="测试数据",ProgressValue=20, Duration=TimeSpan.FromHours(1),TimeRemaining="123",TotalSeconds=100,
             SuccessAndProgressDatas=new(){ new SuccessAndProgressData(null) { ProgressValue=20, RunTime=TimeSpan.FromMinutes(10), TimeRemaining="1234", SchemeName="222", TotalSeconds=20, Speeds = new([1f,2f,1f]) } }
        } } } };
        public ProgressValue CurrentProgressValue => new ProgressValue(ProgressStatisticsList.Sum(p => p.CompletedSeconds), ProgressStatisticsList.Sum(p => p.TotalSeconds));
        public int CompletedCount => ProgressStatisticsList.Sum(p => p.CompletedCount);
        public int ChildsCounts => ProgressStatisticsList.Sum(p => p.ChildsCount);
        public ProgressValue CompletedCountProgressValue => new(CompletedCount, ChildsCounts);
        public void Add(string ClipName, string FragmentName, int FragmentID, TimeSpan FragmentDuration, SuccessAndProgress successAndProgress, bool IsAfterprocessingElement = false)
        {
            IProgressStatistics? cps = ProgressStatisticsList.FirstOrDefault(p => p.Name.Equals(ClipName, StringComparison.OrdinalIgnoreCase));
            if (cps == null)
            {
                cps = new ClipProgressStatistics();
                cps.Name = ClipName;
                ProgressStatisticsList.Add(cps);
            }
            cps.Add(FragmentID, FragmentName, FragmentDuration, successAndProgress, IsAfterprocessingElement);
        }

        public void Add(string FilePathOrClipName, TimeSpan FileDuration, SuccessAndProgress successAndProgress)
        {
            IProgressStatistics? cps = ProgressStatisticsList.FirstOrDefault(p => p.Name.Equals(FilePathOrClipName, StringComparison.OrdinalIgnoreCase));
            if (cps == null)
            {
                cps = new FileProgressStatistics();
                cps.Name = FilePathOrClipName;
                ProgressStatisticsList.Add(cps);
            }
            cps.Add(FilePathOrClipName.GetHashCode(), FilePathOrClipName, FileDuration, successAndProgress);
        }

        public void Remove(string ClipName)
        {
            IProgressStatistics? cps = ProgressStatisticsList.FirstOrDefault(p => p.Name.Equals(ClipName, StringComparison.OrdinalIgnoreCase));
            if (cps != null)
            {
                ProgressStatisticsList.Remove(cps);
                cps.Release();
            }
        }

        public void Update(int ID, TimeSpan? FragmentDuration, SuccessAndProgress? successAndProgress)
        {
            IProgressStatistics? clip = ProgressStatisticsList.FirstOrDefault(p => p.ContainsKey(ID));
            clip?.Update(ID, FragmentDuration, successAndProgress);
        }
    }

    [AddINotifyPropertyChangedInterface]
    internal class ClipProgressStatistics : IProgressStatistics
    {
        public Dictionary<int, FragmentProgressStatistics> FragmentProgressStatisticsDic = new();
        public ObservableCollection<ISubItem> ProgressItems { get; set; } = new();
        public ObservableCollection<ISubItem> AfterprocessingProgressItems { get; set; } = new();
        public string Name { get; set; } = string.Empty;
        public string DisplayName => Name;
        public string SchemesNames => Tools.MergeSchemesNamesToUIText((ProgressItems?.FirstOrDefault()?.SuccessAndProgressDatas?.Select(p => p.SchemeName) ?? [])
            .Union(AfterprocessingProgressItems?.SelectMany(p => p.SuccessAndProgressDatas?.Select(p => p.SchemeName) ?? []) ?? []));
        public double ProgressValue { get; set; } = 0d;
        public string TimeRemaining { get; set; } = "N/A";
        public double TotalSeconds { get; set; }
        public TimeSpan Duration { get; set; } = TimeSpan.Zero;
        public string DisplayDuration => $"[{Tools.GetTimeSpanToString_Digit(Duration, true, false)}]";
        public double CompletedSeconds { get; private set; }
        public bool IsCompleted => ProgressValue > SuccessAndProgressData.ProgressCriticalValue;
        public int CompletedCount => ProgressItems.Sum(p => p.CompletedCount) + AfterprocessingProgressItems.Sum(p => p.CompletedCount);
        public int ChildsCount => ProgressItems.Sum(p => p.ChildsCount) + AfterprocessingProgressItems.Sum(p => p.ChildsCount);
        public void Add(int ID, string Name, TimeSpan DurationTime, SuccessAndProgress successAndProgress, bool IsAfterprocessingElement = false)
        {
            if (!FragmentProgressStatisticsDic.ContainsKey(ID))
            {
                FragmentProgressStatistics current = new FragmentProgressStatistics();
                FragmentProgressStatisticsDic.Add(ID, current);
                if (IsAfterprocessingElement)
                    AfterprocessingProgressItems.Add(current);
                else
                    ProgressItems.Add(current);
                current.ProgressValueChangeEvent += Current_ProgressValueChangeEvent;
            }
            FragmentProgressStatisticsDic[ID].Add(Name, DurationTime, successAndProgress);
            TotalSeconds = ProgressItems.Sum(p => p.TotalSeconds) + AfterprocessingProgressItems.Sum(p => p.TotalSeconds);
            Duration = new TimeSpan(ProgressItems.Sum(p => p.Duration.Ticks)) + new TimeSpan(AfterprocessingProgressItems.Sum(p => p.Duration.Ticks));
        }
        public void Update(int ID, TimeSpan? FragmentDuration, SuccessAndProgress? successAndProgress)
        {
            if (FragmentProgressStatisticsDic.ContainsKey(ID))
                FragmentProgressStatisticsDic[ID].Update(FragmentDuration, successAndProgress);
            TotalSeconds = ProgressItems.Sum(p => p.TotalSeconds) + AfterprocessingProgressItems.Sum(p => p.TotalSeconds);
            Duration = new TimeSpan(ProgressItems.Sum(p => p.Duration.Ticks)) + new TimeSpan(AfterprocessingProgressItems.Sum(p => p.Duration.Ticks));
        }
        public void Release() 
        {
            if(ProgressItems!=null)
            {
                ProgressItems.ForEach(p => p.Release());
                ProgressItems.Clear();
                ProgressItems = null!;
            }
            if(AfterprocessingProgressItems!=null) 
            {
                AfterprocessingProgressItems.ForEach(p => p.Release());
                AfterprocessingProgressItems.Clear();
                AfterprocessingProgressItems = null!;
            }
            if (FragmentProgressStatisticsDic != null)
            {
                FragmentProgressStatisticsDic.Clear(); 
                FragmentProgressStatisticsDic = null!;
            }
        }
        public bool ContainsKey(int FragmentID) => FragmentProgressStatisticsDic.ContainsKey(FragmentID);
        private IEnumerable<ISubItem>? ActiveElements;
        private int ActiveElementsCount;

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void PreparePhase()
        {
            CompletedSeconds = ProgressItems.Sum(p => p.CompletedSeconds) + AfterprocessingProgressItems.Sum(p => p.CompletedSeconds);
            ActiveElements = FragmentProgressStatisticsDic.Values.Where(p => p.CompletedSeconds > 0.0001d);
            ActiveElementsCount = ActiveElements.Count();
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void ComputingTimeRemaining()
        {
            if (ActiveElementsCount < 1)
                return;
            TimeSpan AverageRunTime = TimeSpan.Zero;

            try
            {
                //double AverageSpeed = ActiveElements.Sum(p => p.Speed) / ActiveElementsCount;
                AverageRunTime = TimeSpan.FromMilliseconds(ActiveElements!.Sum(p => p.RunTime.TotalMilliseconds) / ActiveElementsCount);
                //TimeRemaining = $"剩余:[{Tools.GetTimeSpanToString_Digit(TimeSpan.FromSeconds((100d - ProgressValue) / AverageSpeed), true, false)}]";
                TimeRemaining = $"剩余:[{Tools.GetTimeSpanToString_Digit(AverageRunTime * (100d - ProgressValue) / ProgressValue, true, false)}]";
            }
            catch (Exception exc)
            {
                LogManage.WriteExceptionInfo("时间进程计算异常", new TimeProggressCalclateException($"当前参数值： [AverageRunTime:{AverageRunTime}][ProgressValue:{ProgressValue}]", exc), true);
            }
            
        }

        private void Current_ProgressValueChangeEvent(ISubItem sender, SuccessAndProgressData ProgressData, double value)
        {
            PreparePhase();
            value = CompletedSeconds / TotalSeconds * 100;
            ProgressValue = value < SuccessAndProgressData.ProgressCriticalValue ? value : 100d;
            ComputingTimeRemaining();
            ProgressStatistics.Instance.SendPropertyChanged(nameof(ProgressStatistics.Instance.CurrentProgressValue));
            //ProgressStatistics.WriteLOG($"[{DisplayName}][{sender.DisplayName}][{Math.Round(ProgressData.ProgressValue, 2, MidpointRounding.AwayFromZero)}];" +
            //    $"[{Math.Round(ProgressData.CompletedTimingSeconds, 2, MidpointRounding.AwayFromZero)}/{Math.Round(ProgressData.TotalSeconds, 2, MidpointRounding.AwayFromZero)}];" +
            //    $"Source:[{Math.Round(ProgressData.SourceCompletedTimingSeconds, 2, MidpointRounding.AwayFromZero)}/{Math.Round(ProgressData.SourceTotalValue, 2, MidpointRounding.AwayFromZero)}]", true);
        }

    }

    [AddINotifyPropertyChangedInterface]
    internal class FragmentProgressStatistics : ISubItem
    {
        public event Action<ISubItem, SuccessAndProgressData, double>? ProgressValueChangeEvent;
        public int FragmentID { get; set; }
        public ObservableCollection<SuccessAndProgressData> SuccessAndProgressDatas { get; set; } = new();
        public string SchemesNames => Tools.MergeSchemesNamesToUIText(SuccessAndProgressDatas.Select(p => p.SchemeName));
        public string Name = "Fragment";
        public string DisplayName => Name;
        public double ProgressValue { get; set; } = 0d;
        public string TimeRemaining { get; set; } = "N/A";
        public double Speed { get; set; } = 0d;
        //[DependsOn("ProgressValue")] public float CurrentSpeed => SuccessAndProgressDatas.Where(p => !p.IsCompleted).FirstOrDefault()?.CurrentSpeed ?? 0;
        //[DependsOn("ProgressValue")] public string ShowCurrentSpeed => $"Speed: {MathF.Round(CurrentSpeed,2,MidpointRounding.AwayFromZero)}x";
        //[DependsOn("ProgressValue")] public float CurrentAverageSpeed => SuccessAndProgressDatas.Where(p => !p.IsCompleted).FirstOrDefault()?.CurrentAverageSpeed ?? 0;
        //[DependsOn("ProgressValue")] public string $"AverageSpeed: {MathF.Round(CurrentAverageSpeed, 2, MidpointRounding.AwayFromZero)}x";
        public double TotalSeconds { get; set; } = 0d;
        public TimeSpan Duration { get; set; } = TimeSpan.Zero;
        public string DisplayDuration => $"[{Tools.GetTimeSpanToString_Digit(Duration, true, false)}]";
        public double CompletedSeconds { get; private set; } = 0d;
        public bool IsCompleted => ProgressValue > SuccessAndProgressData.ProgressCriticalValue;
        public int CompletedCount => SuccessAndProgressDatas.Count(p => p.IsCompleted);
        public int ChildsCount => SuccessAndProgressDatas.Count;
        public TimeSpan RunTime { get; set; } = TimeSpan.Zero;
        public void Add(string Name, TimeSpan FragmentDuration, SuccessAndProgress successAndProgress)
        {
            this.Name = Name;
            if (FragmentDuration > Duration)
                Duration = FragmentDuration;
            SuccessAndProgressData m_SuccessAndProgressData = new(successAndProgress);
            SuccessAndProgressDatas.Add(m_SuccessAndProgressData);
            TotalSeconds = SuccessAndProgressDatas.Sum(p => p.TotalSeconds);
            m_SuccessAndProgressData.OnProgressChangeEvent += SuccessAndProgress_ProgressChangeEvent;
        }
        public void Update(TimeSpan? FragmentDuration, SuccessAndProgress? successAndProgress)
        {
            if (FragmentDuration.HasValue && FragmentDuration.Value > TimeSpan.Zero)
                Duration = FragmentDuration.Value;
            if (successAndProgress == null)
                return;
            SuccessAndProgressData? successDate = SuccessAndProgressDatas.FirstOrDefault(p => p.SourceEquals(successAndProgress));
            if (successDate == null)
                return;
            successDate.Update();
            TotalSeconds = SuccessAndProgressDatas.Sum(p => p.TotalSeconds);
        }
        private bool StartFlage = false;
        private DateTime startTime = DateTime.MinValue;

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void PreparePhase()
        {
            if (!StartFlage) { startTime = DateTime.Now; StartFlage = true; }
            RunTime = DateTime.Now - startTime;
            CompletedSeconds = SuccessAndProgressDatas.Sum(p => p.CompletedTimingSeconds);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void ComputingTimeRemaining()
        {
            try
            {
                TimeRemaining = $"剩余:[{Tools.GetTimeSpanToString_Digit(RunTime * (100d - ProgressValue) / ProgressValue, true, false)}]";
                Speed = ProgressValue / RunTime.TotalSeconds;
            }
            catch (Exception exc)
            {

                LogManage.WriteExceptionInfo("时间进程计算异常", new TimeProggressCalclateException($"当前参数值： [RunTime:{RunTime}][ProgressValue:{ProgressValue}]", exc), true);
            }
            
        }

        private void SuccessAndProgress_ProgressChangeEvent(SuccessAndProgressData sender, double value)
        {
            PreparePhase();
            value = CompletedSeconds / TotalSeconds * 100;
            ProgressValue = value < SuccessAndProgressData.ProgressCriticalValue ? value : 100d;
            ComputingTimeRemaining();
            ProgressValueChangeEvent?.Invoke(this, sender, ProgressValue);
        }

        public void Release()
        {
            if (SuccessAndProgressDatas != null)
            {
                SuccessAndProgressDatas.ForEach(p => p.Release());
                SuccessAndProgressDatas.Clear();
                SuccessAndProgressDatas = null!;
            }
            ProgressValueChangeEvent = null;
        }

    }


    [AddINotifyPropertyChangedInterface]
    internal class FileProgressStatistics : IProgressStatistics, ISubItem
    {
        public ObservableCollection<ISubItem> ProgressItems { get; set; } = new();
        public ObservableCollection<ISubItem> AfterprocessingProgressItems { get; set; } = null!;
        public ObservableCollection<SuccessAndProgressData> SuccessAndProgressDatas { get; set; } = new();
        public string SchemesNames => Tools.MergeSchemesNamesToUIText(SuccessAndProgressDatas?.Select(p => p.SchemeName)?? []);
        public string Name { get; set; } = string.Empty;
        public string DisplayName => Path.GetFileName(Name);
        public double ProgressValue { get; set; }
        public string TimeRemaining { get; set; } = "N/A";
        public double Speed { get; set; } = 0;

        //[DependsOn("ProgressValue")] public float CurrentSpeed => SuccessAndProgressDatas.Where(p => !p.IsCompleted).FirstOrDefault()?.CurrentSpeed ?? 0;
        //[DependsOn("ProgressValue")] public string ShowCurrentSpeed => $"Speed: {MathF.Round(CurrentSpeed,2,MidpointRounding.AwayFromZero)}x";
        //[DependsOn("ProgressValue")] public float CurrentAverageSpeed => SuccessAndProgressDatas.Where(p => !p.IsCompleted).FirstOrDefault()?.CurrentAverageSpeed ?? 0;
        //[DependsOn("ProgressValue")] public string $"AverageSpeed: {MathF.Round(CurrentAverageSpeed, 2, MidpointRounding.AwayFromZero)}x";

        public double TotalSeconds { get; set; } = 0d;
        public TimeSpan Duration { get; set; } = TimeSpan.Zero;
        public string DisplayDuration => $"[{Tools.GetTimeSpanToString_Digit(Duration, true, false)}]";
        public double CompletedSeconds { get; private set; } = 0d;
        public bool IsCompleted => ProgressValue > SuccessAndProgressData.ProgressCriticalValue;
        public int CompletedCount => SuccessAndProgressDatas.Count(p => p.IsCompleted) + AfterprocessingProgressItems?.Count(p => p.IsCompleted) ?? 0;
        public int ChildsCount => SuccessAndProgressDatas.Count + AfterprocessingProgressItems?.Count ?? 0;
        public TimeSpan RunTime { get; set; } = TimeSpan.Zero;
        public FileProgressStatistics() { ProgressItems.Add(this); }
        public void Add(int ID, string Name, TimeSpan DurationTime, SuccessAndProgress successAndProgress, bool IsAfterprocessingElement = false)
        {
            this.Name = Name;
            if (DurationTime > Duration)
                Duration = DurationTime;
            SuccessAndProgressData m_SuccessAndProgressData = new(successAndProgress);
            if (IsAfterprocessingElement)
            {
                if (AfterprocessingProgressItems == null)
                    AfterprocessingProgressItems = new();
                AfterprocessingProgressItems.Add(this);
            }
            //else { ProgressItems.Add(this); }
            SuccessAndProgressDatas.Add(m_SuccessAndProgressData);
            TotalSeconds = SuccessAndProgressDatas.Sum(p => p.TotalSeconds);
            m_SuccessAndProgressData.OnProgressChangeEvent += SuccessAndProgress_ProgressChangeEvent;
        }
        private bool StartFlage = false;
        private DateTime startTime = DateTime.MinValue;

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void PreparePhase()
        {
            if (!StartFlage) { startTime = DateTime.Now; StartFlage = true; }
            RunTime = DateTime.Now - startTime;
            CompletedSeconds = SuccessAndProgressDatas.Sum(p => p.CompletedTimingSeconds) + (AfterprocessingProgressItems?.Sum(p => p.CompletedSeconds) ?? 0);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void ComputingTimeRemaining()
        {
            try
            {
                TimeRemaining = $"剩余:[{Tools.GetTimeSpanToString_Digit(RunTime * (100d - ProgressValue) / ProgressValue, true, false)}]";
                Speed = ProgressValue / RunTime.TotalSeconds;
            }
            catch (Exception exc)
            {
                LogManage.WriteExceptionInfo("时间进程计算异常", new TimeProggressCalclateException($"当前参数值： [RunTime:{RunTime}][ProgressValue:{ProgressValue}]", exc), true);
            }
        }

        private void SuccessAndProgress_ProgressChangeEvent(SuccessAndProgressData sender, double value)
        {
            PreparePhase();
            value = CompletedSeconds / TotalSeconds * 100;
            ProgressValue = value < SuccessAndProgressData.ProgressCriticalValue ? value : 100d;
            ComputingTimeRemaining();
            ProgressStatistics.Instance.SendPropertyChanged(nameof(ProgressStatistics.Instance.CurrentProgressValue));
        }

        public void Release() 
        {
            if (SuccessAndProgressDatas != null)
            {
                SuccessAndProgressDatas.ForEach(p => p.Release());
                SuccessAndProgressDatas.Clear();
                SuccessAndProgressDatas = null!;
            }
            if (ProgressItems != null)
            {
                ProgressItems.Clear();
                ProgressItems = null!;
            }
            if (AfterprocessingProgressItems != null)
            {
                AfterprocessingProgressItems.Clear();
                AfterprocessingProgressItems = null!;
            }
        }

        public void Update(int ID, TimeSpan? FragmentDuration, SuccessAndProgress? successAndProgress) => ((ISubItem)this).Update(FragmentDuration, successAndProgress);

        void ISubItem.Update(TimeSpan? FragmentDuration, SuccessAndProgress? successAndProgress)
        {
            if (FragmentDuration.HasValue && FragmentDuration.Value > TimeSpan.Zero)
                Duration = FragmentDuration.Value;
            if (successAndProgress == null)
                return;
            SuccessAndProgressData? successDate = SuccessAndProgressDatas.FirstOrDefault(p => p.SourceEquals(successAndProgress));
            if (successDate == null)
                return;
            successDate.Update();
            TotalSeconds = SuccessAndProgressDatas.Sum(p => p.TotalSeconds);
        }

        bool IProgressStatistics.ContainsKey(int FragmentID) => throw new NotImplementedException();
    }

    [AddINotifyPropertyChangedInterface]
    internal class SuccessAndProgressData
    {
        public const double ProgressCriticalValue = 99.99d;
        public event Action<SuccessAndProgressData, double>? OnProgressChangeEvent;
        private SuccessAndProgress? Source;
        public double SourceTotalValue => (Source?.TotalSeconds ?? 0d).GetValid();
        public double SourceCompletedTimingSeconds => (Source?.CompletedTimingSeconds ?? 0d).GetValid();
        private bool StartFlage = false;
        private DateTime startTime = DateTime.MinValue;
        private DateTime LastTime = DateTime.MinValue;
        private TimeSpan IntervalTime = TimeSpan.Zero;
        public double CompletedTimingSeconds = 0d;
        public double TotalSeconds = 0d;
        public TimeSpan RunTime = TimeSpan.Zero;
        public bool IsCompleted => ProgressValue > ProgressCriticalValue;
        public double ProgressValue { get; set; } = 0d;
        public string TimeRemaining { get; set; } = "N/A";
        public string SchemeName { get; set; } = "Empty";
        public float TotalSpeed { get; set; } = 0f;
        public NumberHistoricalStack<float> Speeds = new(10);
        [DependsOn("ProgressValue")] public float CurrentSpeed => Speeds.Count > 0 ? Speeds[0] : 0f;
        [DependsOn("ProgressValue")] public float CurrentAverageSpeed => Speeds.AverageValue;
        [DependsOn("ProgressValue")] public string ShowSpeed => $"Speed: {MathF.Round(CurrentSpeed, 2, MidpointRounding.AwayFromZero).ToString().PadLeft(5,'0')}x|AverageSpeed: {MathF.Round(Speeds.AverageValue, 2, MidpointRounding.AwayFromZero).ToString().PadLeft(5, '0')}x|TotalSpeed: {MathF.Round(TotalSpeed, 2, MidpointRounding.AwayFromZero).ToString().PadLeft(5, '0')}x";

        public SuccessAndProgressData(SuccessAndProgress? successAndProgress)
        {
            if (successAndProgress == null)
                return;
            Source = successAndProgress;
            Source.ProgressChangeEvent += Source_ProgressChangeEvent;
            SchemeName = successAndProgress.SchemeName;
            TotalSeconds = successAndProgress.TotalSeconds;
            ProgressStatistics.Instance.successAndProgresses.Add(Source);
        }
        public void Update()
        {
            if (Source == null)
                return;
            TotalSeconds = Source.TotalSeconds;
        }
        public bool SourceEquals(SuccessAndProgress? obj) => obj == null ? false : obj == Source;

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void PreparePhase()
        {
            DateTime CurrentTime = DateTime.Now;
            if (!StartFlage)
            {
                startTime = CurrentTime;
                StartFlage = true;
            }
            else 
            {
                IntervalTime = CurrentTime - LastTime;
                RunTime = CurrentTime - startTime;
            }
            LastTime = CurrentTime;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void ComputingTimeRemaining()
        {
            try
            {
                TimeRemaining = $"剩余:[{Tools.GetTimeSpanToString_Digit(RunTime * (100d - ProgressValue) / ProgressValue, true, false)}]";
                TotalSpeed = (float)Math.Round(CompletedTimingSeconds / RunTime.TotalSeconds,4,MidpointRounding.AwayFromZero);
            }
            catch (Exception exc)
            {
                LogManage.WriteExceptionInfo("时间进程计算异常", new TimeProggressCalclateException($"当前参数值： [RunTime:{RunTime}][ProgressValue:{ProgressValue}]", exc), true);
            }
        }
        
        private void Source_ProgressChangeEvent(double value)
        {
            PreparePhase();
            if (IntervalTime > TimeSpan.Zero)
            {
                TimeSpan ProcessTime = TimeSpan.FromSeconds(value - CompletedTimingSeconds);
                Speeds.Push((float)Math.Round(ProcessTime / IntervalTime, 4, MidpointRounding.AwayFromZero));
            }
            CompletedTimingSeconds = value;

            value = CompletedTimingSeconds / TotalSeconds * 100;
            ProgressValue = value < ProgressCriticalValue ? value : 100d;
            ComputingTimeRemaining();
            OnProgressChangeEvent?.Invoke(this, ProgressValue);
        }

        public void Release() { if (Source == null) return; ProgressStatistics.Instance.successAndProgresses.Remove(Source); Source.ReleaseScript(); Source = null; OnProgressChangeEvent = null; }
    }


    [Serializable]
    public class TimeProggressCalclateException : Exception
    {
        public TimeProggressCalclateException() { }
        public TimeProggressCalclateException(string message) : base(message) { }
        public TimeProggressCalclateException(string message, Exception inner) : base(message, inner) { }
        [Obsolete]protected TimeProggressCalclateException(
          System.Runtime.Serialization.SerializationInfo info,
          System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
    }
}
